<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>探测雷达</title>
  <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  <link rel="stylesheet" href="/static/css/bbfont.css">
  <link rel="stylesheet" href="/static/css/style.css">
  <link rel="stylesheet" href="qv.css">
  <script src="/static/js/echarts.4.9.js"></script>
  <style>
		:root {
			--box-color: #ccc;
		}

		* {
			margin: 0;
			padding: 0;
		}

    #ims > * {
      font-size: 14px;
    }

		.CCC > * {
			height: 24px !important;
			padding: 1px 5px;
			margin: 0;
			border: none;
			outline: none;
			vertical-align: top;
		}


		.xh {
			width: 100%;
			height: calc((100vh - 34px) / 3);
			position: relative;
			display: flex;
		}

		.xh:not(:first-child) {
			border-top: solid 1px #ccc;
		}

		.xh > div {
			position: relative;
			width: 50%;
			height: 100%;
		}
    .xh > div > .title {
      height: 20px;
      padding-top: 4px;
      width: 100%;
      padding-left: 10px;
		}
		.xh > .ib > img.i, .xh > .ib > img.cbar, .xh > .cb > .c {
			position: absolute;
			top: 34px;
			height: calc(100% - 70px);
		}
    .btitle{
      position: absolute;
      bottom: 0;
      left: 0;
      width: 100%;
      text-align: center;
    }

    .xh > .cb > .c {
			width: 100%;
      height: calc(100% - 50px);
			/*height: calc(100% - 24px);*/
		}

		.xh > .ib > img.i {
			left: 60px;
			/*right: 40px;*/
			width: calc(100% - 120px);
			border: solid #333;
			border-width: 0 0 1px 1px;
		}
    .xh > .ib > .ltitle{
      position: absolute;
      height: calc(50% - 40px);
      writing-mode: vertical-lr;
      text-orientation: sideways;
      transform: translate(10px, 50%) rotate(180deg);
    }

		svg.iaxe {
			position: absolute;
			width: calc(100% - 60px);
			height: 100%;
			left: 0;
			top: 0;
			font-size: 12px;
		}
    svg{pointer-events: none}
		svg.iaxe * {
			font-size: 12px;
		}

		.xh > .ib > img.cbar {
			right: 40px;
			width: 10px;
		}

		svg.cbaraxe {
			position: absolute;
			right: 0px;
			width: 40px;
			top: 0;
			height: 100%;
		}



		.tk {
			dominant-baseline: central;
			text-anchor: middle;
		}

		.tk-top {
			dominant-baseline: text-after-edge;
		}

		.tk-left {
			text-anchor: end;
		}

		.tk-right {
			text-anchor: start;
		}

		.tk-bottom {
			dominant-baseline: text-before-edge;
		}

		svg path {
			stroke-width: 1;
			stroke: #000
		}

		svg path.line {
			stroke: #F00
		}
    .one_box{
      width: 100%;
      height: calc( (100vh - 40px));
      position: relative;
    }
    .one_box .t {
			position: absolute;
			top: 0;
      left: 0;
      height:30px;
      width: 100%;
      padding-left: 10px;
		}
    .one_box .c {
			position: absolute;
			top: 20%;
      left: 25%;
      height: calc( 60% - 60px ) ;
      width: 50%;
		}

    #CCC, .CCC {
      padding: unset;
    }
  /*  离谱*/

  </style>
</head>
<body id="viewer" class="M3">
  <div id="CCC" style="padding: 4px 6px;display: flex; flex-wrap: nowrap">
    <button class="btn btn-primary btn-sm " onclick="main.realtime()" id="realtime">实时</button>
    <button class="btn btn-primary btn-sm mx-1 disactive-btn" id="history" onclick="main.history()">历史</button>
    日期:
    <input id="day" type="date" value="" >
    任务:
    <select id="task" class="sele-comp" style="max-width: 290px;">
    </select>
    工作模式:
    <select id="modes" class="sele-comp" onchange="main.onMode()"></select>

    <div id="imgMenu" class="flex-grow-1 d-flex" style="align-items: center">
      最大帧:
      <label id="frm_max" class="pe-1"></label>
        当前帧:
      <input id="frm_input" oninput="this.nextElementSibling.value=this.value" style="width: 60px" maxlength="4" onchange="main.onFrm(this.value)">
      <input oninput="this.previousElementSibling.value=this.value" style="flex-grow: 1;padding:0;"
             id="frm_range" type="range" min="0" max="0" value="0" step="1" onchange="main.frame(this.value)">
      <button id="frm_img_table" class="btn btn-primary btn-sm" style="display: none"></button>
      <label class="CCC">
        累加间隔: <input type="text" style="max-width: 120px" id="acc_interval" onchange="main.onAcc()">
        <button class="btn btn-primary btn-sm" id="acc" onclick="main.onAcc()">累加</button>
      </label>

    </div>
    <div class="flex-grow-1"></div>
    <button class="btn btn-primary btn-sm"  onclick="main.exportCSV(this)"><i class="fa fa-file-text"></i>下载帧信息</button>
  </div>
  <div style="height: calc(100vh - 50px);background: #fff" class="d-flex flex-row">
    <div class="flex-grow-1 d-flex flex-column position-relative overflow-auto" id="ims">

    </div>

  </div>
  <script src="/static/js/jquery-3.6.0.min.js"></script>
  <script src="/static/js/xtool.js?12"></script>
  <script src="acsr.js"></script>
  <script src="qv.js"></script>
  <script>
    // todo oa data postion :/home/shk/_root/DASWORK
    function genFreqs(freqType, stepV) {
      // unit MHz
      const FREQ_META = {
        0: {
          bw: 40,
          stepUnitV: 0.01,
          f0: 150,
          splitNumber: 8
        }, 1: {
          bw: 1200,
          stepUnitV: 0.02,
          f0: 900,
          splitNumber: 16
        }
      }
      meta = FREQ_META[freqType]
      freqStep = stepV * meta.stepUnitV
      pulseNum = meta.bw / freqStep + 1
      fc = (pulseNum - 1) / 2 + 1
      freqs = Array.from({length: pulseNum}, (_, i) => {
        return Number((meta.f0 + (i + 1 - fc) * freqStep).toFixed(2))
      })
      return freqs
    }

    const MODE_META = {
      // 0：低频，1高频，2高低频混合
      35: {n: '噪声测量模式1', freqType: 0},
      36: {n: '噪声测量模式2', freqType: 1},
      37: {n: '低频测量模式1', freqType: 0},
      38: {n: '高频测量模式1', freqType: 1},
      39: {n: '低频测量模式2', freqType: 0},
      40: {n: '高频测量模式2', freqType: 1},
      41: {n: '定标模式', freqType: 0},
      42: {n: '交替测量模式1', freqType: 2},
      43: {n: '交替测量模式2', freqType: 2}
    }
    MODE = Object.keys(MODE_META).reduce((acc,k)=> {acc[k] = MODE_META[k].n ;return acc;} ,{})



    $CE = (v, options = {}) => {
      let el = document.createElementNS('http://www.w3.org/2000/svg', v)
      Object.keys(options).forEach(k => {
        el.setAttribute(k, options[k]);
      });
      return el;
    }
    const FREQS = {
      0: genFreqs(0, 20),
      1: genFreqs(1, 10)
    }

    class CharViewer {

      constructor(p, pEle, freqType) {
        $$('#imgMenu').style.display='none'
        this.freqType = freqType
        this.freqs = FREQS[freqType]
        this.p = p
        this.k = ['l_v', 'l_h']
        if(freqType) this.k = 'h_a'
        // pEle.querySelector('.t').textContent = freqType == 0? '低频 噪声功率谱': '高频 噪声功率谱'
        this.c = echarts.init(pEle.querySelector('.c'))
      }
      resize() {
        this.c.resize();
      }
      render(resp, index) {
        this.c.setOption(this.option(resp))
      }
      option(resp) {

        if (this.freqType) {
          let tmpdata = resp[this.k]
          return {
            animation: false,
            color: ['#00b', '#f00'],
            title: {text:'高频 噪声功率谱', left: 'center', textStyle: {fontSize: 16}, top: 0},
            legend: {top: 15, right: 30},
            tooltip: {trigger: 'axis'},
            dataZoom: [{id: this.k,type: 'inside'}],
            grid: {top: 70, left: 60, bottom: 50, right: 30},
            xAxis: {type: 'value', name: '频率(MHz)', nameLocation:'center', nameGap:30, min: this.freqs[0], max: this.freqs[this.freqs.length-1]},
            yAxis: {type: 'value', name: '功率(dB)', scale: true},
            series: {id: 'a', type: 'line', symbol: 'none', data: tmpdata.map((v,i) => {
              return v <-998.0? [this.freqs[i], NaN]: [this.freqs[i],v]}
              )}
          }
        }
        return {
                  animation: false,
                  color: ['#00b', '#f00'],
                  title: {text: '低频 噪声功率谱', left: 'center', textStyle: {fontSize: 16}, top: 0},
                  legend: {top: 15, right: 30},
                  tooltip: {trigger: 'axis'},
                  dataZoom: [{id: this.k,type: 'inside'}],
                  grid: {top: 70, left: 60, bottom: 50, right: 30},
                  xAxis: {type: 'value', name: '频率(MHz)', nameLocation:'center',nameGap:30,  min: this.freqs[0], max: this.freqs[this.freqs.length-1]},
                  yAxis: {type: 'value', name: '功率(dB)', },
                  series: [{id: 'v', name: '低频V', type: 'line', symbol: 'none', data: resp[this.k[0]].map((v,i)=> v <-998.0? [this.freqs[i], NaN]: [this.freqs[i],v])},
                          {id: 'h', name: '低频H', type: 'line', symbol: 'none', data: resp[this.k[1]].map((v,i)=> v <-998.0? [this.freqs[i], NaN]: [this.freqs[i],v])}]
                }
      }
    }

    class ImViewer {
      constructor(p, pEle, freqType, name, k) {
        $$('#imgMenu').style.display='flex'
        this.freqType = freqType
        this.samples = FREQS[freqType].map((_,i)=>i+1)
        this.p = p
        this.k = k
        pEle.querySelector('.ib>.title').textContent = name + '各帧的脉压结果(dB)';
        this.$img = pEle.querySelector('.ib > .i')
        this.$iaxe = pEle.querySelector('.ib>.iaxe')
        this.$cbaraxe = pEle.querySelector('.ib>.cbaraxe')
        pEle.querySelector('.cb>.title').textContent = name + '脉压结果(dB)'
        this.c = echarts.init(pEle.querySelector('.cb > .c'))
        this.c.setOption({
          animation: false,
          legend: {top: -5, right: 20},
          color: ['#084eb5','#b55808','red','grey'],
          tooltip: {trigger: 'axis'},
          dataZoom: [{id: this.k,type: 'inside'}],
          grid: {top: 14, left: 60, bottom: 25, right: 30},
          xAxis: {type: 'value', min: this.samples[0], max: this.samples[this.samples.length-1]},
          yAxis: {type: 'value'},
          series: [{id: 'v0', type: 'line', symbol: 'none', lineStyle:{width: 1},data: []},
                  {id: 'vn', type: 'line', symbol: 'none', lineStyle:{width: 1},data: []}]
        })
        this.init(p)
      }

      addTick(ax, x, y, v, dx, dy) {
        let cls = 'tk '
        if (dy) cls += dy > 0 ? 'tk-bottom' : 'tk-top';
        if (dx) cls += dx > 0 ? 'tk-right' : 'tk-left';
        let label = $CE('text', {
          'x': x + dx * 1.5,
          'y': y + dy * 1.5,
          'class': cls,
        });
        label.textContent = v;
        ax.appendChild(label);
        ax.appendChild($CE('path',
          {d: `M${x},${y} L${x + dx},${y + dy}`}))
      }

      resize() {
        this.c.resize();
        this.resetTicks()
      }
      async render(resp, index) {
        if (this.info) {
          let x = this.$img.offsetWidth * index/(this.info.fram.max - this.info.fram.min);
          this.$line.style.transform = `translate(${x}px,0)`
        }

        // this.c.setOption({series: {data: resp[this.k]['sample'][0]}})
        let data = resp[this.k]
        let s = []
        if (data.n) {
          s.push({id: 'v0', name: '一帧', data: data.v0.map((v,i) => [this.samples[i], v])});
          s.push({id: 'vn', name: data.n + '帧', data: data.vn.map((v,i)=> [this.samples[i], v])});
        } else {
          s.push({id: 'v0', name: '一帧', data: data.v0.map((v,i)=> [this.samples[i], v])});
        }
        this.c.setOption({series: s});
      }

      async init(p) {
        let [info, img] = await fetch(`/-/omsp.acsr.hist?t=${this.p.$task.value}&k=${this.k}&mode=${this.p.$modes.value}`).then(v => [v.headers.get('info'), v.blob()])
        this.$img.src = URL.createObjectURL(await img)
        this.info = info = JSON.parse(info)
        this.$img.onclick = this.click.bind(this)
        this.resetTicks()
      }

      resetTicks() {
        let info = this.info
        let T = this.$img.offsetTop, L = this.$img.offsetLeft, H = this.$img.offsetHeight, W = this.$img.offsetWidth;
        if (this._iax) this._iax.remove();
        this.$iaxe.appendChild(this._iax = $CE('g', {transform: `translate(${L},${T})`}));
        let i;
        let sampleDH = H / (info.sample.max - info.sample.min)
        info.sample.ticks.forEach((v, i) => this.addTick(
          this._iax, 0, (v - info.sample.min) * sampleDH, v, -3, 0
        ))
        let frmDH = W / (info.fram.max - info.fram.min)
        info.fram.ticks.forEach((v, i) => this.addTick(
          this._iax, (v - info.fram.min) * frmDH, H, v, 0, 3))
        if(this._barax) this._barax.remove()
        this.$cbaraxe.appendChild(this._barax = $CE('g', {transform: `translate(0,${T})`}))
        let barDH = H / (info.cbar.max - info.cbar.min);
        info.cbar.ticks.forEach((v, i) => this.addTick(
          this._barax, 0, H - (v - info.cbar.min) * barDH, v, 3, 0))
        this.$line = $CE('path', {
          d: 'M0,0L0,' + H,
          class: 'line',
        })
        this.$line.style.transform = 'translate(-100px,0)'
        this._iax.append(this.$line)
      }

      click(ev) {
        let x = ev.layerX
        let frmid = parseInt((this.info.fram.max - this.info.fram.min) * x / this.$img.offsetWidth);
        this.p.frame(frmid)
      }
    }

    class XPage extends Realtime {
      constructor(task) {
        // $STATION ||
        super('ACSR', getStation(),Params)
        if(task){
          this._task = task
          this.cur_task = task.task
          this.$day.value = task.date()
        }
        this.voiceModes = [35, 36]
        this.$root = $$('#ims')
        this.$modes = $$('#modes')
        this.$accInter = $$('#acc_interval')
        this.renderMode()
        this.$day.onchange = this.onDay.bind(this)
        this.$task.onchange = this.onTask.bind(this)
        this.iviewer = []
        this.vmax = 0
        this.vmin = 0
        window.onresize = this.onresize.bind(this)

      }
      reset() {
        super.reset();
        this.resetIms()
      }

      resetIms() {
        this.$root.innerHTML = ''
        this.iviewer = []
        let frameInfo = this.frames[0]
        if(frameInfo==undefined) return
        // if(frameInfo.mode == 41) return
        let l = frameInfo.frm[1], h = frameInfo.frm[2]
        // 噪声模式
        if (this.voiceModes.includes(frameInfo.mode) ){
          this.$root.innerHTML = `<div class="one_box">
                                    <div class="t"></div>
                                    <div class="c"></div>
                                  </div>`
          this.$xhs = this.$root.querySelector('.one_box')
          this.iviewer.push(new CharViewer(this, this.$xhs, MODE_META[frameInfo.mode].freqType))
          return
        }

        this.$root.innerHTML = Array(l*2+h).fill(0).map((_,i) => `
          <div class="xh">
            <div class="ib">
              <div class="title"></div>
              <div class="ltitle">脉冲数</div>
              <img src="ACSR/blk.bmp" class="i"/>
              <svg class="iaxe"></svg>
              <svg class="cbaraxe"></svg>
              <img src="./ACSR/cbar.png" class="cbar">
              <div class="btitle">帧号</div>
            </div>
            <div class="cb">
              <div class="title"></div>
              <div class="c"></div>
              <div class="btitle">脉冲数</div>
            </div>
          </div>
        `).join('')
        this.$xhs = this.$root.querySelectorAll('.xh')
        this.iviewer = []
        let i = 0
        for (let j = 0; j < l; j++) {
          this.iviewer.push(new ImViewer(this, this.$xhs[i], 0, '低频 V', 'l_v'))
          this.iviewer.push(new ImViewer(this, this.$xhs[i + 1], 0, '低频 H', 'l_h'))
          i += 2
        }
        for (let j = 0; j < h; j++) {
          this.iviewer.push(new ImViewer(this, this.$xhs[i], 1, '高频', 'h_a'))
          i += 1
        }

      }

      onFrm(frmid) {
       let id =  parseInt(frmid)
        this.$frmi.textContent = id
        this.frame(id)
      }

      onAcc() {
        this.frame(this.$frmr.value, true)
      }
      requestData(accFlag) {
        let inter = parseInt(this.$accInter.value);

        if(!accFlag || !inter  ) inter = 1
        let frmIndex = parseInt(this.$frmr.value);
        let infos = this.frames.slice(frmIndex, frmIndex+inter)
        let data = {
          f: this.$task.value,
          infos: infos,

        }
        return data
      }

      async onMode() {
        let m = this.$modes.value
        if (!m) return
        this.filter_frames(m)
        this.resetIms()
        await this.frame(this.$frmr.value, false)
      }

      async frame(fid, accFlag) {
        let task = this.$task.value
        if(!task) return
        let d = this.frames[fid];
        if(d==undefined) return
        this.$frmi.value = this.$frmr.value = fid

        // let resp = await $api(`omsp.acsr.rt?f=${this.$task.value}&offset=${d.frm[0]}&L=${d.frm[1]}&H=${d.frm[2]}`)
        if (this.voiceModes.includes(parseInt(this.$modes.value))) {
          let resp = await $api(`omsp.acsr.hist_voice?f=${task}&m=${this.$modes.value}`)
          this.iviewer.forEach(im=>im.render(resp))
          return
        }
        let resp = await $api('omsp.acsr.hist_chart',this.requestData(accFlag), v=>v.json())
        this.iviewer.forEach(im => im.render(resp,fid))
      }


      async onTask() {
        this.$root.innerHTML = ''
        await this.load_frames(this.$task.value)
        if(this.frames.length<0) this.reset()
        this.onMode()
      }


      async onDay(e) {
        let day = this.$day.value
        if(!day) return;
        this._task = this.cur_task = ''
        await this.load_task(this.$day.value);

      }

      seek(index) {
        this.resetIms()
        let fr = this.frames[index]
        if(fr){
          this.frame(index, false)
        }
      }
      realtime() {
        window.location.href = 'ACSR.html'
      }
      async load_frames(task) {
        await super.load_frames(task);
        let m = this.$modes.value
        this.frames = this.frames_ori.filter(v => v.mode == m)
        this.frame_max = this.frames.length -1
        this.frame_index = this.$frmr.max
        /*this.$frmr.max = this.$frmr.value = -1
        this.$frmi.value = ''*/

      }

      async load_frame(info) {
        let d = {f: this.$task.value, sample: 1, frm: [0, 1, 0], mode: 37}
        let frmD = await $api('omsp.acsr_his', d, v => v.json())
        if (frmD.max > this.vmax) this.vmax = frmD.max
        if (frmD.min < this.vmin) this.vmin = frmD.min
        this.d.push(frmD)
      }

      onresize() {
        this.iviewer.forEach(v=>v.resize())
      }
      async history() {
        await super.history();
      }


    }
    var main;
    var station;
    (async()=>{
      let params = new URLSearchParams(window.location.search);
      let t = params.get('t')
      console.log(t)
      let task = t ? new Task(t) : ''
      main = new XPage(task)
      await main.history()
    })()
  </script>
</body>
</html>